
/**
 * Handles the automatic reconnection process. Every time a connection is dropped without
 * the application explicitly closing it, the manager automatically tries to reconnect to
 * the server.<p>
 * <p/>
 * The reconnection mechanism will try to reconnect periodically:
 * <ol>
 * <li>First it will try 6 times every 10 seconds.
 * <li>Then it will try 10 times every 1 minute.
 * <li>Finally it will try indefinitely every 5 minutes.
 * </ol>
 *
 * @author Francisco Vives
 */
class ReconnectionManager : public ConnectionListener {
public:
	
    void connectionClosed() {
        done = true;
    }

	//void connectionClosedOnError(Exception e) ;

    void reconnectingIn(int seconds) {
        // ignore
    }

	//ignore
    //void reconnectionFailed(Exception e) ; 

    /**
     * The connection has successfull gotten connected.
     */
    void reconnectionSuccessful() {
        // ignore
    }

protected:	
    /**
     * Sets the time elapsed between each reconnection attempt.
     * It is used when the client has lost the server connection and the XMPPConnection
     * automatically tries to reconnect.
     *
     * @param secondBetweenReconnection The number of seconds between reconnection.
     */
    void setSecondBetweenReconnection( int secondBetweenReconnection) {
        this->secondBetweenReconnection = secondBetweenReconnection;
    }

    /**
     * Starts a reconnection mechanism if it was configured to do that.
     * The algorithm is been executed when the first connection error is detected.
     * <p/>
     * The reconnection mechanism will try to reconnect periodically in this way:
     * <ol>
     * <li>First it will try 6 times every 10 seconds.
     * <li>Then it will try 10 times every 1 minute.
     * <li>Finally it will try indefinitely every 5 minutes.
     * </ol>
     */
    void reconnect() ;
	
    /**
     * Fires listeners when a reconnection attempt has failed.
     *
     * @param exception the exception that occured.
     */
    //void notifyReconnectionFailed(Exception exception);

    /**
     * Fires listeners when The XMPPConnection will retry a reconnection. Expressed in seconds.
     *
     * @param seconds the number of seconds that a reconnection will be attempted in.
     */
    void notifyAttemptToReconnectIn(int seconds) ;
	
private:
	class ReconnectionThread : public Thread {
	public:
		ReconnectionThread( ReconnectionManager * reconnectionManager) {
			this->reconnectionManager = reconnectionManager;
		}	
	protected:
		virtual void run( void * arg) {
			while( reconnectionManager->isReconnectionAllowed() && remainingSeconds > 0) {
				sleepMills( notificationPeriod);
				--remainingSeconds;
				this->notifyAttemptToReconnectIn( remainingSeconds);
			}
            // Waiting time have finished

            // Makes the reconnection attempt
			if( reconnectionManager->isReconnectionAllowed()) {
				// Attempts to reconnect.
				reconnectionManager->connection->connect();
			}
		}
	private:
		ReconnectionManager * reconnectionManager;
		/**
         * Holds the number of reconnection attempts
         */
        int attempts ;
        int firstReconnectionPeriod ; // 6 attempts
        int secondReconnectionPeriod ; // 16 attempts
        int firstReconnectionTime ; // 10 seconds
        int secondReconnectionTime ; // 1 minute
        int lastReconnectionTime ; // user defined in seconds
        int remainingSeconds ; // The seconds remaining to a reconnection
        int notificationPeriod ; // 1 second

        /**
         * Returns the amount of time until the next reconnection attempt.
         *
         * @return the amount of time until the next reconnection attempt.
         */
        int timeDelay() {
        	if (attempts > secondReconnectionPeriod) { return lastReconnectionTime; }// 5 minutes 
            if (attempts > firstReconnectionPeriod) { return secondReconnectionTime; }// 1 minute
            
			return firstReconnectionTime; // 10 seconds
        }

	};

    ReconnectionManager(XMPPConnection * connection) :
		connection(connection),
		done(false)
	{}

    /**
     * Returns true if the reconnection mechanism is enabled.
     *
     * @return true if automatic reconnections are allowed.
     */
    bool isReconnectionAllowed() ;

    /**
     * Returns the time elapsed between each reconnection attempt.
     * By default it will try to reconnect every 5 minutes.
     * It is used when the client has lost the server connection and the XMPPConnection
     * automatically tries to reconnect.
     *
     * @return Returns the number of seconds between reconnection.
     */
    int getSecondBetweenReconnection() {
        return secondBetweenReconnection;
    }


	
	// Holds the time elapsed between each reconnection attempt
    int secondBetweenReconnection  // 5 minutes

    // Holds the thread that produces a periodical reconnection.
    Thread * reconnectionThread;

    // Holds the connection to the server
    XMPPConnection * connection;

	// Holds the state of the reconnection
    bool done ;
};
